from contentforge.utils.logger import logger, log_method
import traceback
import gradio as gr
import os
from dotenv import load_dotenv
from contentforge.core.model_factory import ModelFactory, ModelType
from contentforge.core.model_interface import ModelConfig
from contentforge.utils.web_scraper import fetch_content_from_url

# 加载环境变量
load_dotenv()


class ContentForgeApp:
    def __init__(self):
        # 模型配置映射
        self.model_configs = {
            ModelType.OPENAI: {
                "models": [
                    "gpt-4o",
                    "gpt-4o-mini",
                    "gpt-o1",
                    "gpt-o1-mini",
                    "gpt-3.5-turbo", 
                    "gpt-4", 
                    "gpt-4-turbo"
                ],
                "default_model": os.getenv('OPENAI_MODEL_NAME', 'gpt-4o'),
                "api_key": os.getenv('OPENAI_API_KEY', ''),
                "api_base": os.getenv('OPENAI_API_BASE', 'https://api.openai.com/v1')
            },
            ModelType.CLAUDE: {
                "models": [
                    "claude-3-5-sonnet-20241022", 
                    "claude-3-5-haiku-20241022",
                    "claude-3-sonnet-20240229", 
                    "claude-3-opus-20240229", 
                ],
                "default_model": os.getenv('CLAUDE_MODEL_NAME', 'claude-3-5-haiku-20241022'),
                "api_key": os.getenv('CLAUDE_API_KEY', ''),
                "api_base": os.getenv('CLAUDE_API_BASE', 'https://api.anthropic.com')
            },
            ModelType.KIMI: {
                "models": [
                    "moonshot-v1-8k", 
                    "moonshot-v1-32k", 
                    "moonshot-v1-128k"
                ],
                "default_model": os.getenv('KIMI_MODEL_NAME', 'moonshot-v1-8k'),
                "api_key": os.getenv('KIMI_API_KEY', ''),
                "api_base": os.getenv('KIMI_API_BASE', 'https://api.moonshot.cn/v1')
            }
        }
        
        # 行业和写作风格预设
        self.industries = [
            "科普", "科技", "金融", "教育", "医疗", "营销",
            "电商", "娱乐", "旅游", "法律", "创业", "通用"
        ]
        
        self.writing_styles = [
            "学术严谨", "通俗易懂", "专业权威", "轻松幽默", 
            "简洁清晰", "情感丰富", "技术细致", "创意独特"
        ]

    def load_prompt_template(self, platform: str) -> str:
        """根据平台加载提示词模板"""
        platform_map = {
            "公众号": "wechat",
            "知乎": "zhihu",
            "小红书": "xiaohongshu",
            "B站": "bilibili",
            "抖音": "douyin",
            "微博": "weibo",
            "其他": "other"
        }
        template_file = f"contentforge/prompts/{platform_map.get(platform, 'other')}.txt"
        with open(template_file, 'r', encoding='utf-8') as f:
            return f.read()

    def _create_model_config(
        self, 
        model_type: ModelType, 
        model_name: str, 
        api_key: str
    ) -> ModelConfig:
        """
        创建模型配置
        """
        config_info = self.model_configs.get(model_type, {})
        
        return ModelConfig(
            api_key=api_key,
            model_name=model_name or config_info.get('default_model', 'default'),
            api_base=config_info.get('api_base'),
            max_tokens=8192,  # 根据模型调
            temperature=0.7
        )

    @log_method('info')
    def rewrite_content(
        self, 
        content: str, 
        model_type_str: str,
        model_name: str,
        api_key: str,
        industry: str, 
        content_type: str, 
        target_audience: str, 
        professional_level: int, 
        writing_style: str,
        is_url: bool = False,
        output_format: str = "Markdown",
        output_platform: str = "公众号"
    ) -> tuple[str, str, str]:
        """
        重写文章内容
        """
        try:
            logger.info(f"开始重写文章，模型类型: {model_type_str} {is_url}")
            
            # 验证API Key
            if not api_key or api_key.strip() == '':
                error_msg = f"错误：{model_type_str.upper()}模型的API Key不能为空"
                logger.error(error_msg)
                return (
                    error_msg,  # rewritten_content
                    "请输入有效的API Key",  # suggestions
                    error_msg  # error_output
                )
            
            # 如果是链接，获取内容
            if is_url == '链接':
                if not content.strip():
                    return (
                        "无法获取链接内容",  # rewritten_content
                        "请检查链接是否正确",  # suggestions
                        "获取链接内容失败"  # error_output
                    )
                content = fetch_content_from_url(content)
                if not content:
                    return (
                        "无法获取链接内容",  # rewritten_content
                        "请检查链接是否正确",  # suggestions
                        "获取链接内容失败"  # error_output
                    )
            
            # 转换模型类型
            model_type = ModelType(model_type_str.lower())
            
            # 创建模型配置
            model_config = self._create_model_config(model_type, model_name, api_key)
            
            # 创建模型实例
            model = ModelFactory.create_model(model_type, model_config)
            
            # 加载平台对应的提示词模板
            prompt_template = self.load_prompt_template(output_platform)
            
            # 准备提示词
            prompt = prompt_template.format(
                content=content,
                industry_field=industry,
                content_type=content_type,
                target_audience=target_audience,
                professional_level=professional_level,
                writing_style=writing_style,
                output_format=output_format
            )
            
            # 生成文本
            messages = [{"role": "user", "content": prompt}]
            rewritten_content = model.generate_text(messages)
    
            logger.info(f"文章重写成功，原文长度: {len(content)}, 重写后长度: {len(rewritten_content)}")
            
            return (
                rewritten_content,  # rewritten_content
                "",  # error_output (空字符串表示无错误)
                ""  # suggestions
            )
        
        except ValueError as ve:
            # 模型类型错误
            error_msg = f"模型选择错误：{str(ve)}"
            logger.error(error_msg)
            return (
                error_msg,  # rewritten_content
                "请选择有效的模型类型", 
                error_msg
            )
        
        except Exception as e:
            error_msg = f"文章重写失败：{str(e)}"
            logger.error(error_msg)
            logger.error(traceback.format_exc())
            
            return (
                error_msg,  # rewritten_content
                "无法生成优化建议，请检查API Key和网络连接",  # error_output
                error_msg
            )

    def create_gradio_interface(self):
        """创建Gradio界面"""
        with gr.Blocks(title="ContentForge - 智能内容重构") as demo:
            gr.Markdown("# 🚀 ContentForge - 智能内容重构")
            
            with gr.Row():
                with gr.Column():
                    # 模型选择
                    model_type_dropdown = gr.Dropdown(
                        choices=[type.value for type in ModelType], 
                        label="选择模型类型", 
                        value=ModelType.OPENAI.value
                    )
                    
                    # 动态模型名称下拉框
                    model_name_dropdown = gr.Dropdown(label="选择模型版本")
                    
                    # API Key输入
                    api_key_input = gr.Textbox(
                        label="API Key", 
                        type="password", 
                        placeholder="输入API Key"
                    )
                    
                    # 输入类型选择
                    input_type_radio = gr.Radio(
                        choices=["文本", "链接"], 
                        label="输入类型", 
                        value="文本"
                    )
                    
                    # 输入区域
                    input_content = gr.Textbox(label="原始文章或链接", lines=10)
                    
                    # 输出格式选择
                    output_format_radio = gr.Radio(
                        choices=["原样式", "Markdown", "HTML"], 
                        label="输出格式", 
                        value="原样式"
                    )
                    
                    with gr.Row():
                        industry_dropdown = gr.Dropdown(
                            choices=self.industries, 
                            label="行业领域", 
                            value="通用"
                        )
                        content_type_input = gr.Textbox(label="文章类型", value="技术文章")
                    
                    with gr.Row():
                        target_audience_input = gr.Textbox(label="目标受众", value="专业读者")
                        writing_style_dropdown = gr.Dropdown(
                            choices=self.writing_styles, 
                            label="写作风格", 
                            value="创意独特"
                        )
                    # 输出平台选择
                    output_platform_radio = gr.Radio(
                        choices=["公众号", "知乎", "小红书", "B站", "抖音", "微博", "其他"], 
                        label="输出平台", 
                        value="公众号"
                    )
                    professional_level = gr.Slider(
                        minimum=1, maximum=5, step=1, 
                        label="专业程度", value=3
                    )
                    
                    rewrite_btn = gr.Button("🔄 重构文章")
                
                with gr.Column():
                    # 输出区域
                    output_content = gr.Textbox(label="重构后文章", lines=10)                    
                    # 添加错误处理组件
                    error_output = gr.Textbox(
                        label="错误信息", 
                        visible=True,  # 默认可见
                        interactive=False,  # 不可编辑
                        lines=2
                    )
            
            # 模型类型变更时更新模型版本和API Key
            def update_model_details(model_type_str):
                """更新模型详情的处理函数"""
                try:
                    logger.info(f"开始更新模型详情，模型类型: {model_type_str}")
                    
                    # 安全地获取模型类型
                    try:
                        model_type = ModelType(model_type_str.lower())
                    except ValueError:
                        return {
                            model_name_dropdown: gr.Dropdown(choices=[]),
                            api_key_input: "",
                            error_output: f"无效的模型类型: {model_type_str}"
                        }
                    
                    # 获取选中模型类型的配置
                    config_info = self.model_configs.get(model_type, {})
                    if not config_info:
                        return {
                            model_name_dropdown: gr.Dropdown(choices=[]),
                            api_key_input: "",
                            error_output: f"找不到模型类型 {model_type_str} 的配置"
                        }
                    
                    models = config_info.get('models', [])
                    default_model = config_info.get('default_model')
                    api_key = config_info.get('api_key', '')
                    
                    # 使用默认模型或列表中的第一个
                    selected_model = default_model if default_model in models else (models[0] if models else None)
                    
                    logger.info(f"模型列表: {models}, 选中模型: {selected_model}")
                    
                    # 返回更新后的值
                    return [
                        gr.Dropdown.update(choices=models, value=selected_model),
                        api_key,
                        ""  # 清空错误信息
                    ]
                    
                except Exception as e:
                    error_msg = f"更新模型配置失败: {str(e)}"
                    logger.error(f"{error_msg}\n{traceback.format_exc()}")
                    return [
                        gr.Dropdown.update(choices=[]),
                        "",
                        error_msg
                    ]

            # 修改模型类型变更事件
            model_type_dropdown.change(
                fn=update_model_details,
                inputs=[model_type_dropdown],
                outputs=[model_name_dropdown, api_key_input, error_output]
            )

            # 初始化模型版本（使用OpenAI作为默认）
            demo.load(
                fn=lambda: update_model_details(ModelType.OPENAI.value),
                inputs=None,
                outputs=[model_name_dropdown, api_key_input, error_output]
            )
            
            # 交互逻辑
            rewrite_btn.click(
                fn=self.rewrite_content, 
                inputs=[
                    input_content, model_type_dropdown, model_name_dropdown, 
                    api_key_input, industry_dropdown, content_type_input, 
                    target_audience_input, professional_level, 
                    writing_style_dropdown, input_type_radio, output_format_radio, output_platform_radio
                ],
                outputs=[output_content, error_output],
                api_name="rewrite"  # 添加API名称
            )
        
        return demo

def create_app():
    """创建应用实例的工厂函数"""
    logger.info("正在创建ContentForge应用实例")
    return ContentForgeApp()

def same_auth(username, password):
    # 添加多用户
    users = {
        "admin": "sunjackson1234"
    }
    if os.getenv('USERS', ''):
        users.update({user.split(':')[0]: user.split(':')[1] for user in os.getenv('USERS').split(',')})
    if username in users and users[username] == password:
        logger.info(f"用户 {username} 验证成功")
        return True
    logger.info(f"用户 {username} 验证失败")
    return False


@log_method('info')
def launch_app():
    """启动Gradio应用"""
    try:
        logger.info("开始启动ContentForge Gradio应用")
        
        # 日志：创建应用实例前
        logger.info("准备创建应用实例")
        app = create_app()
        logger.info("启动实例创建成功")
        
        # 日志：创建Gradio界面前
        logger.info("准备创建Gradio界面")
        demo = app.create_gradio_interface()
        logger.info("Gradio界面创建成功")
        
        # 日志：启动Gradio前
        logger.info("准备启动Gradio服务")
        demo.launch(
            auth=same_auth,
            server_name="127.0.0.1", 
            server_port=8080,
            share=False,
            debug=True  # 开启调试模式
        )
        logger.info("Gradio服务启动完成")
        
    except Exception as e:
        logger.error(f"应用启动失败：{str(e)}")
        logger.error(traceback.format_exc())
        
    finally:
        logger.info("Gradio应用启动流程结束")

if __name__ == "__main__":
    try:
        launch_app()
    except Exception as e:
        logger.critical(f"致命错误：{str(e)}")
        logger.critical(traceback.format_exc())
        print(f"启动失败：{str(e)}")
        print(traceback.format_exc())